﻿using CleanArchitecture.Core;
using CleanArchitecture.Core.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace CleanArchitecture.Infrastructure.Plugins.BaiduFanyiSDK
{
    public class TransResult
    {
        public string src { get; set; }
        public string dst { get; set; }
    }
    public class BaiduFanyiResult
    {
        //Api response Json: 
        //{
	    //    "from": "en",
	    //    "to": "zh",
	    //    "trans_result": 
        //    [{
		//        "src": "apple",
		//        "dst": "\u82f9\u679c"
        //    }]
        //}
        public string from { get; set; }
        public string to { get; set; }
        public IList<TransResult> trans_result { get; set; }
        public string error_code { get; set; }
        public string error_msg { get; set; }
    }
    public class BaiduFanyiRequest
    {
        //Utf8编码
        public string q { get; set; }
        public string from { get; set; }
        public string to { get; set; }
        public string salt { get; set; }
        public string sign { get; set; }
    }
    public class BaiduFanyiSDK
    {
        private const string FanyiApiUrl = "http://api.fanyi.baidu.com/api/trans/vip/translate";

        //https://www.cnblogs.com/cdyy/p/9789731.html
        private static string MD5(string password)
        {
            try
            {
                System.Security.Cryptography.HashAlgorithm hash = System.Security.Cryptography.MD5.Create();
                byte[] hash_out = hash.ComputeHash(Encoding.UTF8.GetBytes(password));

                var md5_str = BitConverter.ToString(hash_out).Replace("-", "");
                return md5_str.ToLower();
            }
            catch
            {

                throw;
            }
        }

        private static string UrlEncode(string str)
        {
            str = System.Web.HttpUtility.UrlEncode(str);
            byte[] buf = Encoding.ASCII.GetBytes(str);//等同于Encoding.ASCII.GetBytes(str)
            for (int i = 0; i < buf.Length; i++)
                if (buf[i] == '%')
                {
                    if (buf[i + 1] >= 'a') buf[i + 1] -= 32;
                    if (buf[i + 2] >= 'a') buf[i + 2] -= 32;
                    i += 2;
                }
            return Encoding.ASCII.GetString(buf);//同上，等同于Encoding.ASCII.GetString(buf)
        }

        private static string HttpBuildQuery(string appid, string skey, BaiduFanyiRequest requst)
        {
            //Step1. 将请求参数中的 APPID(appid)， 翻译query(q, 注意为UTF-8编码), 随机数(salt), 以及平台分配的密钥(可在管理控制台查看) 按照 appid+q+salt+密钥 的顺序拼接得到字符串1。
            //Step2.对字符串1做md5，得到32位小写的sign。
            var sign = CaculateMd5Sign(appid, requst.q, requst.salt, skey);
            StringBuilder sb = new StringBuilder();
            sb.Append(FanyiApiUrl);
            sb.Append("?q=" + UrlEncode(requst.q));
            sb.Append("&from=" + requst.from);
            sb.Append("&to=" + requst.to);
            sb.Append("&appid=" + appid);
            sb.Append("&salt=" + requst.salt);
            sb.Append("&sign=" + sign);            
            return sb.ToString();
        }
        #region 百度提供.net版SDK MD5算法有问题
        //private static string MD5(string password)
        //{
        //    byte[] textBytes = System.Text.Encoding.UTF8.GetBytes(password);
        //    try
        //    {
        //        System.Security.Cryptography.MD5CryptoServiceProvider cryptHandler;
        //        cryptHandler = new System.Security.Cryptography.MD5CryptoServiceProvider();
        //        byte[] hash = cryptHandler.ComputeHash(textBytes);
        //        string ret = "";
        //        foreach (byte a in hash)
        //        {
        //            ret += a.ToString("x");
        //        }
        //        return ret;
        //    }
        //    catch
        //    {
        //        throw;
        //    }
        //}

        //private static string UrlEncode(string str)
        //{
        //    str = System.Web.HttpUtility.UrlEncode(str);
        //    byte[] buf = Encoding.ASCII.GetBytes(str);//等同于Encoding.ASCII.GetBytes(str)
        //    for (int i = 0; i < buf.Length; i++)
        //        if (buf[i] == '%')
        //        {
        //            if (buf[i + 1] >= 'a') buf[i + 1] -= 32;
        //            if (buf[i + 2] >= 'a') buf[i + 2] -= 32;
        //            i += 2;
        //        }
        //    return Encoding.ASCII.GetString(buf);//同上，等同于Encoding.ASCII.GetString(buf)
        //}

        //private static string HttpBuildQuery(IDictionary<string, string> querystring_arrays)
        //{

        //    StringBuilder sb = new StringBuilder();
        //    foreach (var item in querystring_arrays)
        //    {
        //        sb.Append(UrlEncode(item.Key));
        //        sb.Append("=");
        //        sb.Append(UrlEncode(item.Value));
        //        sb.Append("&");
        //    }
        //    sb.Remove(sb.Length - 1, 1);
        //    return sb.ToString();
        //}
        #endregion
        private static string CaculateMd5Sign(string appid, string query, string salt, string sn)
        {
            var utf8 = Encoding.UTF8;
            byte[] utfBytes = utf8.GetBytes(query);
            var utf8query = utf8.GetString(utfBytes);
            return MD5(appid+utf8query+salt+sn);
        }
        /// <summary>
        /// DavidLee 2020/02/20 增加开启/关闭使用BaiduFanyiSDK方法，避免以后其他网站不使用的情况
        /// </summary>
        /// <param name="client"></param>
        /// <param name="nowaConfig"></param>
        /// <param name="loginIp"></param>
        /// <returns></returns>
        public static async Task<BaiduFanyiResult> TranslateAsync(HttpClient client, NowaConfig nowaConfig, BaiduFanyiRequest requst)
        {
            if (string.IsNullOrEmpty(requst.from)) requst.from = "auto";
            if (string.IsNullOrEmpty(requst.to)) requst.to = "auto";
            if (string.IsNullOrEmpty(nowaConfig.BaiduFanyiAPPID) || string.IsNullOrEmpty(nowaConfig.BaiduFanyiSecretKey))
                return null;
            if (string.IsNullOrEmpty(requst.salt)) throw new ArgumentNullException(nameof(requst.salt));
            //https://fanyi-api.baidu.com/doc/21

            string baidutransrequstUrl = HttpBuildQuery(nowaConfig.BaiduFanyiAPPID, nowaConfig.BaiduFanyiSecretKey, requst);            
            //DavidLee Dont set timeout before task cancelled
            //client.Timeout = TimeSpan.FromMilliseconds(timeout <= 60 ? 60 : timeout);
            var request = new HttpRequestMessage(HttpMethod.Get, baidutransrequstUrl);
            var response = await client.SendAsync(request);
            //do something for response
            if (!response.IsSuccessStatusCode) throw new NowaException("Http Get Response Error");
            var resultStr = response.Content.ReadAsStringAsync().Result;
            BaiduFanyiResult transresult = JsonConvert.DeserializeObject<BaiduFanyiResult>(resultStr);
            if (transresult != null && (!string.IsNullOrEmpty(transresult.error_code) && transresult.error_code != "52000")) throw new NowaException($"Baidu Fanyi SDK Error: {transresult.error_msg}");
            else
            {
                request.Dispose();
                return transresult;
            }
        }
    }

}
